//
// JsonRpc++ Copyright (c) 2007 by Peter Wang
//

#ifndef _JSONRPCSERVER_H_
#define _JSONRPCSERVER_H_

#if defined(_MSC_VER)
# pragma warning(disable:4786)    // identifier was truncated in debug info
#endif

#ifndef MAKEDEPEND
# include <map>
# include <string>
#endif

#include "JsonRpcUtil.h"
#include "JsonRpcDispatch.h"
#include "JsonRpcSource.h"
#include "JsonRpcServerMethod.h"

namespace JsonRpc {


  typedef void ( *methodExecuteHook_t)(const std::string& ,Json::Value& , Json::Value& );

  // Class representing connections to specific clients
  class JsonRpcServerConnection;

  //! A class to handle JSON RPC requests
  class JsonRpcServer : public JsonRpcSource {
  public:
    //! Create a server object.
    JsonRpcServer();
    //! Destructor.
    virtual ~JsonRpcServer();

    //! Specify whether introspection is enabled or not. Default is not enabled.
    void enableIntrospection(bool enabled=true);

    //! Add a command to the RPC server
    JsonRpcServerMethod* addMethod(JsonRpcServerMethod* method);

    template < class R >
    JsonRpcServerMethod* addMethod(const char *methodName, 
        R (*fun)(), 
        std::string const& help="", const void *context=NULL)
    {
    return addMethod( new Wrapper::FunctionWrapper0 < R >(this, 
        methodName, fun, help, context));
    }

    template < class R , class T1>
    JsonRpcServerMethod* addMethod(std::string const& methodName, 
        R (*fun)(T1), 
        std::string const& help="", const void *context=NULL)
    {
    return addMethod( new Wrapper::FunctionWrapper1 < R, T1 >(this, 
        methodName, fun, help, context));
    }

    template < class R , class T1, class T2>
    JsonRpcServerMethod* addMethod(std::string const& methodName, 
        R (*fun)(T1, T2), 
        std::string const& help="", const void *context=NULL)
    {
    return addMethod( new Wrapper::FunctionWrapper2 < R, T1, T2 >(this, 
        methodName, fun, help, context));
    }

    template < class R , class T1, class T2, class T3>
    JsonRpcServerMethod* addMethod(std::string const& methodName, 
        R (*fun)(T1, T2, T3), 
        std::string const& help="", const void *context=NULL)
    {
    return addMethod( new Wrapper::FunctionWrapper3 < R, T1, T2 ,T3>(this, 
        methodName, fun, help, context));
    }

    template < class R , class T1, class T2, class T3, class T4>
    JsonRpcServerMethod* addMethod(std::string const& methodName, 
        R (*fun)(T1, T2, T3, T4), 
        std::string const& help="", const void *context=NULL)
    {
    return addMethod( new Wrapper::FunctionWrapper4 < R, T1, T2 ,T3, T4>(this, 
        methodName, fun, help, context));
    }

    template < class R , class T1, class T2, class T3, class T4, class T5>
    JsonRpcServerMethod* addMethod(std::string const& methodName, 
        R (*fun)(T1, T2, T3, T4, T5), 
        std::string const& help="", const void *context=NULL)
    {
    return addMethod( new Wrapper::FunctionWrapper5 < R, T1, T2 ,T3, T4, T5>(this, 
        methodName, fun, help, context));
    }

    template < class R , class T1, class T2, class T3, class T4, class T5, class T6>
    JsonRpcServerMethod* addMethod(std::string const& methodName, 
        R (*fun)(T1, T2, T3, T4, T5, T6), 
        std::string const& help="", const void *context=NULL)
    {
    return addMethod( new Wrapper::FunctionWrapper6 < R, T1, T2 ,T3, T4, T5, T6>(this, 
        methodName, fun, help, context));
    }

    template < class R , class T1, class T2, class T3, class T4, class T5, class T6, class T7>
    JsonRpcServerMethod* addMethod(std::string const& methodName, 
        R (*fun)(T1, T2, T3, T4, T5, T6, T7), 
        std::string const& help="", const void *context=NULL)
    {
    return addMethod( new Wrapper::FunctionWrapper7 < R, T1, T2 ,T3, T4, T5, T6, T7>(this, 
        methodName, fun, help, context));
    }

    template < class A, class R >
    JsonRpcServerMethod* addMethod(const char *methodName, 
        A* obj, R (A::*fun)(), 
        std::string const& help="")
    {
    return addMethod( new Wrapper::MethodWrapper0 < A, R >(this, 
        methodName, obj, fun,  help));
    }

    template < class A, class R , class T1>
    JsonRpcServerMethod* addMethod(std::string const& methodName, 
        A* obj, R (A::*fun)(T1), 
        std::string const& help="")
    {
    return addMethod( new Wrapper::MethodWrapper1 < A, R, T1 >(this, 
        methodName, obj, fun,  help));
    }

    template < class A, class R , class T1, class T2>
    JsonRpcServerMethod* addMethod(std::string const& methodName, 
        A* obj, R (A::*fun)(T1, T2), 
        std::string const& help="")
    {
    return addMethod( new Wrapper::MethodWrapper2 < A, R, T1, T2 >(this, 
        methodName, obj, fun,  help));
    }

    template < class A, class R , class T1, class T2, class T3>
    JsonRpcServerMethod* addMethod(std::string const& methodName, 
        A* obj, R (A::*fun)(T1, T2, T3), 
        std::string const& help="")
    {
    return addMethod( new Wrapper::MethodWrapper3 < A, R, T1, T2 ,T3>(this, 
        methodName, obj, fun,  help));
    }

    template < class A, class R , class T1, class T2, class T3, class T4>
    JsonRpcServerMethod* addMethod(std::string const& methodName, 
        A* obj, R (A::*fun)(T1, T2, T3, T4), 
        std::string const& help="")
    {
    return addMethod( new Wrapper::MethodWrapper4 < A, R, T1, T2 ,T3, T4>(this, 
        methodName, obj, fun,  help));
    }

    template < class A, class R , class T1, class T2, class T3, class T4, class T5>
    JsonRpcServerMethod* addMethod(std::string const& methodName, 
        A* obj, R (A::*fun)(T1, T2, T3, T4, T5), 
        std::string const& help="")
    {
    return addMethod( new Wrapper::MethodWrapper5 < A, R, T1, T2 ,T3, T4, T5>(this, 
        methodName, obj, fun,  help));
    }

    template < class A, class R , class T1, class T2, class T3, class T4, class T5, class T6>
    JsonRpcServerMethod* addMethod(std::string const& methodName, 
        A* obj, R (A::*fun)(T1, T2, T3, T4, T5, T6), 
        std::string const& help="")
    {
    return addMethod( new Wrapper::MethodWrapper6 < A, R, T1, T2 ,T3, T4, T5, T6>(this, 
        methodName, obj, fun,  help));
    }

    template < class A, class R , class T1, class T2, class T3, class T4, class T5, class T6, class T7>
    JsonRpcServerMethod* addMethod(std::string const& methodName, 
        A* obj, R (A::*fun)(T1, T2, T3, T4, T5, T6, T7), 
        std::string const& help="")
    {
    return addMethod( new Wrapper::MethodWrapper7 < A, R, T1, T2 ,T3, T4, T5, T6, T7>(this, 
        methodName, obj, fun,  help));
    }

    //! Remove a command from the RPC server
    void removeMethod(JsonRpcServerMethod* method);

    //! Remove a command from the RPC server by name
    void removeMethod(const std::string& methodName);

    //! Look up a method by name
    JsonRpcServerMethod* findMethod(const std::string& name) const;

    //! Create a socket, bind to the specified port, and
    //! set it in listen mode to make it available for clients.
    bool bindAndListen(int port, int backlog = 5);

    //! Process client requests for the specified time
    void work(double msTime);

    //! Temporarily stop processing client requests and exit the work() method.
    void exit();

    //! Close all connections with clients and the socket file descriptor
    void shutdown();

    //! Introspection support
    void listMethods(Json::Value& result);

    // JsonRpcSource interface implementation

    //! Handle client connection requests
    virtual unsigned handleEvent(unsigned eventType);

    //! Remove a connection from the dispatcher
    virtual void removeConnection(JsonRpcServerConnection*);

	void setMethodExecuteHook(methodExecuteHook_t pHook);

	methodExecuteHook_t _hook_methodExecute;

  protected:

    //! Accept a client connection request
    virtual void acceptConnection();

    //! Create a new connection object for processing requests from a specific client.
    virtual JsonRpcServerConnection* createConnection(int socket);

    // Whether the introspection API is supported by this server
    bool _introspectionEnabled;

    // Event dispatcher
    JsonRpcDispatch _disp;

    // Collection of methods. This could be a set keyed on method name if we wanted...
    typedef std::map< std::string, JsonRpcServerMethod* > MethodMap;
    MethodMap _methods;

    // system methods
    JsonRpcServerMethod* _listMethods;
    JsonRpcServerMethod* _methodHelp;


  };
} // namespace JsonRpc

#endif //_JSONRPCSERVER_H_
